package cn.lingyangwl.agile.pay.pay.listener;

import cn.lingyangwl.agile.pay.common.manager.PayMqSender;
import cn.lingyangwl.agile.pay.common.model.mq.MchNotifyMQ;
import cn.lingyangwl.agile.pay.common.service.MchNotifyRecordService;
import cn.lingyangwl.agile.pay.common.service.PayNodeService;
import cn.lingyangwl.agile.pay.common.service.PayOrderService;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.lingyangwl.agile.pay.model.entity.MchNotifyRecord;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * @author shenguangyang
 */
@Slf4j
@Component
//@RabbitListener(bindings = {
//        @QueueBinding(
//                value = @Queue(value = PayOrderMchNotifyMQ.DELAY_QUEUE, durable = "true"), key = PayOrderMchNotifyMQ.ROUTE_KEY,
//                exchange = @Exchange(value = MqCons.ORDER_EVENT_EXCHANGE, type = ExchangeTypes.TOPIC))
//})
@RabbitListener(queues = MchNotifyMQ.DELAY_QUEUE)
public class MchNotifyListener {

    @Resource
    private PayOrderService payOrderService;
    @Resource
    private MchNotifyRecordService mchNotifyRecordService;
    @Resource
    private PayMqSender payMqSender;
    @Resource
    private PayNodeService payNodeService;

    @RabbitHandler
    public void onMessage(String msg, Channel channel, Message message) {
        try {
            MchNotifyMQ.MsgPayload payload = MchNotifyMQ.parse(msg, MchNotifyMQ.MsgPayload.class);
            log.info("接收商户通知MQ, msg={}", payload);

            Long notifyId = payload.getNotifyId();
            MchNotifyRecord record = mchNotifyRecordService.getById(notifyId);
            if (record == null || !Objects.equals(record.getStatus(), MchNotifyRecord.STATE_ING)) {
                log.info("查询通知记录不存在或状态不是通知中");
                return;
            }
            if (record.getNotifyCount() >= record.getNotifyCountLimit()) {
                log.info("已达到最大发送次数");
                return;
            }

            // 1. (发送结果最多6次)
            int currentCount = record.getNotifyCount() + 1;

            String notifyUrl = record.getNotifyUrl();
            String res = "";
            try {
                int pathEndPos = notifyUrl.indexOf('?');
                if (pathEndPos <= -1) {
                    log.error("通知地址错误，参数为空，notifyUrl：{}", notifyUrl);
                    throw new BizException("通知地址错误");
                }

                res = HttpUtil.post(StrUtil.subPre(notifyUrl, pathEndPos), StrUtil.subSuf(notifyUrl, pathEndPos + 1), 5 * 1000);
            } catch (Exception e) {
                log.error("http error", e);
                res = "连接[" + UrlBuilder.of(notifyUrl).getHost() + "]异常:【" + e.getMessage() + "】";
            }

            // 支付订单 & 第一次通知: 更新为已通知
            if (currentCount == 1 && MchNotifyRecord.TYPE_PAY_ORDER.equals(record.getOrderType())) {
                payOrderService.updateNotifySent(record.getOrderNo());
            }

            // 通知成功
            if ("SUCCESS".equalsIgnoreCase(res)) {
                mchNotifyRecordService.updateNotifyResult(notifyId, MchNotifyRecord.STATE_SUCCESS, res);
                return;
            }

            // 通知次数 >= 最大通知次数时， 更新响应结果为异常， 不在继续延迟发送消息
            if (currentCount >= record.getNotifyCountLimit()) {
                mchNotifyRecordService.updateNotifyResult(notifyId, MchNotifyRecord.STATE_FAIL, res);
                return;
            }

            // 继续发送MQ 延迟发送
            mchNotifyRecordService.updateNotifyResult(notifyId, MchNotifyRecord.STATE_ING, res);
            payMqSender.sendDelay(MchNotifyMQ.build(notifyId), currentCount * 30);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }
}
